/*最近公共祖先(LCA)

* 1.向上标记法O(n)
    (1) 从x向上走到根节点，并标记所有经过的结点
    (2)从y向上走到根节点，当第一次遇到已经标记的结点时，就找到了LCA(x,y);

* 2.树上倍增法O((n+m)logn):预处理O(nlogn),每次查询(logn)
    核心数组fa[i][j]:表示从i结点开始，向上走2^j远的祖先结点, 0<=j<=logn
    (1)bfs得到每个结点所处的深度depth[]。根节点为1，越界结点fa[0]=0, depth[x]表示x的深度。
    (2)用二进制拆分，找到a的，b同深度的祖先。（假设a深度大于b）。
    (3)如果此时a==b，那么b是a祖先结点，此时a就是LCA(a,b);
    (4)如果此时a!=b,我们仍然二进制拆分，使得fa[a][i] == fa[b][i];
    (5)此时 a、b,是最近公共祖先的子节点。fa[a][0] == fa[b][0] == LCA(a,b);

* 3.(tarjan求最近公共祖先) O(n+m)
    tarjan是一种离线查询算法
    所谓离线就是将所有查询先记录下来，然后计算好所有的中间过程，最后再将所有的查询记录对应的结果依次输出

    tarjan是基于向上标记法的一种优化
    首先树上两个结点之间的距离是等于 结点u到根节点的距离 + 结点v到根节点的距离 - 2 * 结点u、v的最近公共祖先到根节点的距离 
                                  <-> dist[u,v] = dist[u] + dist[v] - 2 * dist[LCA(u,v)]

    tarjan算法如何求解最近公共祖先:
    首先它将整棵树上的结点分为三部分
    (1)已经搜索完且回溯过的点 标记为 2
    (2)正在搜索的分支结点 标记为 1
    (3)还未搜索到的结点 标记为 0

    * 核心：
        对于已经被标记为 2 的点 和当前正在搜索的分支存在一种关系，就是
        (1)所有被标记为 2 的点都可以合并压缩到当前正在搜索的分支中的某个结点上，这一步操作可以用并查集实现
        (2)因此当我们搜索完且回溯当前结点的时候，可以遍历关于当前结点u的所有有关询问，
           其中询问中对标记为 2 的结点与当前结点u的最近公共祖先就是标记为 2 的结点在并查集中的代表元素（根节点/祖宗）

* 注意点：
    (1)lca中的第一个for，目的是找到a的，和b同深度的祖先结点。一定要从大到小遍历。
    (2)lca中的第二个for，目的是让a和b分别转移到LCA(a,b)的子节点上，一定要从大到小遍历。
    (3)本题中lca第二个for从小到大遍历也能过，是因为没要求输出正确LCA(a,b),只要求判断。
    (4)第一for目的是让距离t变为0，第二个for目的是让t变为1。
    (5)我们只有从最高位1遍历，才能根据唯一的二进制形式达到要求。

*/

#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
// #define ONLINE_GUDGE
using namespace std;
using PII = pair<int, int>;
const int N = 2e5 + 10, M = N * 2, INF = 0x3f3f3f3f;

int n, m;
int e[M], ne[M], h[N], w[M], idx;
// bool st[N]; 
int depth[N], fa[N], res[N], st[N];
vector<PII> query[N]; // first 存 结点编号 second 存 询问编号


void AddEdge(int a, int b, int c)
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ; // 
}

int find(int x)
{
    return fa[x] == x ? fa[x] : find(fa[x]);
}

void dfs(int u, int fa)
{
    for(int i = h[u]; ~i; i = ne[i])
    {
        int v = e[i];
        if(v == fa) continue; // 每个节点只有一个父节点，只会初始化(访问)一次，在无向图中，只需特判不直接相连即可
        depth[v] = depth[u] + w[i];
            dfs(v, u);
    }
}

void Tarjan(int u)
{
    st[u] = 1;
    for(int i = h[u]; ~i; i = ne[i])
    {
        int v = e[i];
        if(st[v]) continue; 
        Tarjan(v);
        fa[v] = u;
    }

    for(auto item : query[u])
    {
        int v = item.first, id = item.second;
        if(st[v] == 2)
        {
            int anc = find(v); // 公共祖先
            res[id] = depth[u] + depth[v] - depth[anc] * 2;
        }
    }

    st[u] = 2;
}

signed main()
{
    #ifdef ONLINE_JUDGE

    #else
    freopen("./in.txt","r",stdin);
    #endif
    //ios::sync_with_stdio(false);   
	//cin.tie(0);

    cin >> n >> m;
    memset(h, -1, sizeof h);

    // Edge
    for(int i = 0; i < n - 1; i++)
    {
        int a, b, c; cin >> a >> b >> c;
        AddEdge(a, b, c), AddEdge(b, a, c);
    }

    // Query
    for(int i = 0; i < m; i++)
    {
        int a, b; cin >> a >> b;
        if(a != b){
            query[a].push_back({b,i});
            query[b].push_back({a,i});
        }
    }

    for(int i = 1; i <= n; i++) fa[i] = i;
    
    dfs(1, -1);

    Tarjan(1);

    for(int i = 0; i < m; i++) printf("%d\n", res[i]);
    return 0;
}